package unito.likir.io;

import java.util.List;
import java.util.LinkedList;
import java.util.Collection;
import java.util.concurrent.Future;
import java.util.concurrent.ExecutionException;
import java.io.IOException;

import unito.likir.Node;
import unito.likir.NodeId;
import unito.likir.messages.dht.RPCMessage;
import unito.likir.messages.dht.StoreResponse;
import unito.likir.routing.Contact;
import unito.likir.settings.PropFinder;
import unito.likir.settings.Settings;
import unito.likir.storage.StorageEntry;

/**
 * IterativeStoreManager class
 * @author Luca Maria Aiello
 * @version 0.1
 */

public class IterativeStoreManager extends ObservableFutureTask<Integer>
{
	private Node node;
	private NodeId key;
	private String type;
	private byte[] object;
	private long ttl;
	private final int TIME_OUT;
	
	public IterativeStoreManager(Node node, NodeId key, String type, byte[] object, long ttl)
	{
		this.node = node;
		this.key = key;
		this.type = type;
		this.object = object;
		this.ttl = ttl;
		this.TIME_OUT = Integer.parseInt(PropFinder.get(Settings.TIME_OUT));
	}
	
	public void run()
	{
		int storeCounter = 0;
		
		Collection<Contact> nearestToKey = null;
		try
		{
			nearestToKey =  node.lookup(key).get();
		}
		catch (InterruptedException ie)
		{
			set(storeCounter);//TODO: gestisci meglio
		}
		catch (ExecutionException ee)
		{
			set(storeCounter);//TODO: gestisci meglio
		}
		
		if (nearestToKey == null)
		{
			set(0);
			return;
		}
		
		List<Future<RPCMessage>> replies = new LinkedList<Future<RPCMessage>>();
		
		StorageEntry entry = node.getEntryFactory().buildStorageEntry(key, object, type, ttl);
		
		for (Contact c : nearestToKey)
		{
			try
			{
				replies.add(node.store(c, entry));
			}
			catch (IOException ioe)
			{
				System.err.println("ERROR in iterative store");
				ioe.printStackTrace();//log
			}
		}
		
		RPCMessage msg;
		StoreResponse resp;
		for (Future<RPCMessage> futureMsg : replies)
		{
			try
			{
				msg = futureMsg.get(TIME_OUT, Settings.DEFAULT_TIME_UNIT);
				resp = (StoreResponse)msg.getRPC();
				if (resp.getStoreResult())
					storeCounter++;
			}
			catch(Exception e)
			{
				System.err.println("Iterative store: a contact failed to respond");
				//e.printStackTrace();//log
			}
		}
		
		set(storeCounter);
	}
}
